require 'sinatra/base'
require 'warden'

require './models/user'
require './helpers/auth'
require './helpers/response'

class LoginHandler < Sinatra::Base
    include AuthHelpers
    include Responder

    before do
        # set up the default response (empty)
        @r = r()
    end
    
    after do
        # return the response
        @r
    end

    ## LOGIN ROUTES
    post '/login?' do
        content_type :json

        warden_handler.authenticate!
        @r = r('', current_user)
    end

    post '/unauthenticated' do
        @r = r(warden_handler.message||'Invalid Login').to_json
    end

    get '/unauthenticated' do
        @r = r(warden_handler.message||'Invalid Login').to_json
    end

    post '/logout' do
        warden_handler.logout
    end

    get '/logout' do
        warden_handler.logout
    end

    # this is here because its the only other route than does not require authentication
    post '/users/new' do
        @r =  r("That email address is taken")

        if User.first(:email=>params['email']).nil?
            user = User.create(:email=>params['email'], :password => params['password'])
            if not user.save!
                @r = r(user.errors.first.first)
            else
                warden_handler.authenticate!
                @r = r('', current_user)
            end
        end
    end

    ##AUTHENTICATION
    use Warden::Manager do |manager|
        manager.default_strategies :password
        manager.failure_app = self
        manager.serialize_into_session {|user| user.id}
        manager.serialize_from_session {|id| User.get(id)}
    end

    Warden::Strategies.add(:password) do
        def valid?
            params["email"] || params["password"]
        end

        def authenticate!
            # in here:
            #   - receive username, password from client as parameters
            #   - check against user database
            #   - if its a valid login then shoot back the User object and set cookie
            #   - if not, return an error to the client (for them to deal with)
            user = User.authenticate(params["email"], params["password"]) 
            if not user.nil?
                success!(user)
            else
                msg = "Invalid login"
                user = User.first({:email=>params["email"]})
                if not user.nil?
                    user.failures = user.failures + 1
                    if user.failures > 3
                        user.locked = true
                        msg = "This account has been locked"
                    end
                    user.save!
                end
                fail(msg)
            end
        end
    end
end